/*
 * Copyright 2010 Kevin L'Huillier <klhuillier@gmail.com>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.lhuillier.pwsafe.io.v3;


import java.security.SecureRandom;
import org.lhuillier.pwsafe.io.StretchedKey;
import org.lhuillier.pwsafe.io.codec.BinConverter;
import com.google.inject.Inject;


class V3KeyStretcherImpl implements V3KeyStretcher {
    private final SecureRandom random = new SecureRandom();
    private final Crypto crypto;
    private final BinConverter binConv;
    
    @Inject
    V3KeyStretcherImpl(Crypto crypto, BinConverter binConv) {
        this.crypto = crypto;
        this.binConv = binConv;
    }

    @Override
    public StretchedKey stretchKey(byte[] data, String password) {
        byte[] pwBytes = binConv.writeString(password);
        byte[] salt = salt(data);
        int iter = iter(data);
        byte[] key = crypto.stretchKey(pwBytes, salt, iter);
        return new V3StretchedKey(key, salt, iter, crypto, binConv, this);
    }

    @Override
    public StretchedKey createKey(String password) {
        return createKey(password, 2048);
    }
    
    @Override
    public StretchedKey createKey(String password, int iterations) {
        byte[] pwBytes = binConv.writeString(password);
        byte[] salt = newSalt();
        byte[] key = crypto.stretchKey(pwBytes, salt, iterations);
        return new V3StretchedKey(key, salt, iterations, crypto, binConv, this);
    }
    
    @Override
    public StretchedKey resalt(StretchedKey key, String password) {
        return createKey(password, key.getIterations());
    }

    private byte[] newSalt() {
        byte[] result = new byte[32];
        random.nextBytes(result);
        return result;
    }
    
    private byte[] salt(byte[] data) {
        return binConv.slice(data, 4, 32);
    }

    private int iter(byte[] data) {
        return binConv.readInt(data, 36);
    }
}
